package com.xrh.tank;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.util.List;
import java.util.Random;

import javax.swing.ImageIcon;
/**
 * @author 肖荣辉
 * @function 坦克类
 * @date 2014-3-4
 */
public class Tank {
	public static final int XSPEED=5;//在X轴上移动的坦克速度
	public static final int YSPEED=5;//在Y轴移动的坦克速度
	private int x,y;
	private int oldX,oldY;//记录坦克上一次的位置,防止粘住墙
	private boolean bL=false,bU=false,bR=false,bD=false;//代表方向键是否被按下
	public enum Direction {U,D,L,R,RU,RD,LD,LU,STOP};//八个方向和停止的方向,枚举类型
	private Direction dir=Direction.STOP;//默认停止
	private Direction ptDir=Direction.D;//炮筒的方向
	TankClient tc;//声明客户端对象,为了让坦克开火能影响到炮弹的创建
	public static final int WIDTH=65;//坦克宽度
	public static final int HEIGHT=45;//坦克高度
	private boolean good;//区分坦克是敌军还是我军
	private boolean live=true;//区分坦克是死是活
	private static Random r=new Random();//随机数产生器
	private int step=r.nextInt(12)+3;//让坦克移动几步之后才改变方向
	private int life=100;//生命值
	private BloodBar bb=new BloodBar();
	//红军坦克
	ImageIcon[] redTank={
			new ImageIcon(getClass().getResource("images/u_red.png")),
			new ImageIcon(getClass().getResource("images/d_red.png")),
			new ImageIcon(getClass().getResource("images/l_red.png")),
			new ImageIcon(getClass().getResource("images/r_red.png")),
			new ImageIcon(getClass().getResource("images/ru_red.png")),
			new ImageIcon(getClass().getResource("images/rd_red.png")),
			new ImageIcon(getClass().getResource("images/ld_red.png")),
			new ImageIcon(getClass().getResource("images/lu_red.png"))
	};
	//蓝军坦克
	ImageIcon[] blueTank={
			new ImageIcon(getClass().getResource("images/u_blue.png")),
			new ImageIcon(getClass().getResource("images/d_blue.png")),
			new ImageIcon(getClass().getResource("images/l_blue.png")),
			new ImageIcon(getClass().getResource("images/r_blue.png")),
			new ImageIcon(getClass().getResource("images/ru_blue.png")),
			new ImageIcon(getClass().getResource("images/rd_blue.png")),
			new ImageIcon(getClass().getResource("images/ld_blue.png")),
			new ImageIcon(getClass().getResource("images/lu_blue.png"))
	};
	
	public int getX() {
		return x;
	}

	public void setX(int x) {
		this.x = x;
	}

	public int getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
	}

	public int getLife() {
		return life;
	}

	public void setLife(int life) {
		this.life = life;
	}

	public boolean isGood() {
		return good;
	}

	public void setGood(boolean good) {
		this.good = good;
	}

	public boolean isLive() {
		return live;
	}

	public void setLive(boolean live) {
		this.live = live;
	}
	/**
	 * @param x 坦克x坐标
	 * @param y 坦克y轴坐标
	 * @param good 阵营坦克标识
	 */
	public Tank(int x, int y,boolean good) {
		this.x = x;
		this.y = y;
		this.oldX=x;
		this.oldY=y;
		this.good=good;
	}
	/**
	 * 
	 * @param x 坦克的x坐标
	 * @param y 坦克的y坐标
	 * @param good 阵营坦克表示
	 * @param dir 坦克的方向
	 * @param tc 游戏主窗口的引用
	 */
	public Tank(int x, int y,boolean good,Direction dir,TankClient tc) {
		this(x,y,good);
		this.dir=dir;
		this.tc=tc;
	}
	
	/**
	 * 画出坦克
	 * @param g 传入画笔的引用
	 */
	public void draw(Graphics g){
		if(!live){
			if(!good){
				tc.tanks.remove(this);//如果是敌军坦克死亡,则从数组移除
			}
			return;
		}
		Color c=g.getColor();//系统默认的画笔颜色先存放起来,以便随时还原回来
		if(good){
			bb.draw(g);//画出我军血条
		}
		
		//根据炮筒的方向画坦克
		switch(ptDir){
			case U:
				if(good){
					g.drawImage(blueTank[0].getImage(), x, y, null);//我军坦克
				}else{
					g.drawImage(redTank[0].getImage(), x, y, null);
				}
				break;
			case D:
				if(good){
					g.drawImage(blueTank[1].getImage(), x, y, null);//我军坦克
				}else{
					g.drawImage(redTank[1].getImage(), x, y, null);
				}
				
				break;
			case L:
				if(good){
					g.drawImage(blueTank[2].getImage(), x, y, null);//我军坦克
				}else{
					g.drawImage(redTank[2].getImage(), x, y, null);
				}
				break;
			case R:
				if(good){
					g.drawImage(blueTank[3].getImage(), x, y, null);//我军坦克
				}else{
					g.drawImage(redTank[3].getImage(), x, y, null);
				}
				break;
			case RU:
				if(good){
					g.drawImage(blueTank[4].getImage(), x, y, null);//我军坦克
				}else{
					g.drawImage(redTank[4].getImage(), x, y, null);
				}
				break;
			case RD:
				if(good){
					g.drawImage(blueTank[5].getImage(), x, y, null);//我军坦克
				}else{
					g.drawImage(redTank[5].getImage(), x, y, null);
				}
				break;
			case LD:
				if(good){
					g.drawImage(blueTank[6].getImage(), x, y, null);//我军坦克
				}else{
					g.drawImage(redTank[6].getImage(), x, y, null);
				}
				break;
			case LU:
				if(good){
					g.drawImage(blueTank[7].getImage(), x, y, null);//我军坦克
				}else{
					g.drawImage(redTank[7].getImage(), x, y, null);
				}
				break;
		}
		g.setColor(c);//恢复默认画笔颜色
		if(this.dir!=Direction.STOP){
			this.ptDir=this.dir;//每次画完后根据坦克的方向调整炮筒的方向
		}
		move();//因为键盘按完后才产生效果,画完上一个位置,里面把下一个位置给设置好,这就是移动
		
	}
	/**
	 * 	因为键盘在相同的时间内产生的事件不均匀,那么就会造成同样的时间坦克移动的距离不一样
	 * 所以,我们让键盘按下的时候只改变坦克的方向,而不去改变移动位置
	 */
	private void move(){
		this.oldX=x;//记录移动之前的坐标
		this.oldY=y;
		
		switch(dir){
			case U:
				y-=YSPEED;
				break;
			case D:
				y+=YSPEED;
				break;
			case L:
				x-=XSPEED;
				break;
			case R:
				x+=XSPEED;
				break;
			case RU:
				x+=XSPEED;
				y-=YSPEED;
				break;
			case RD:
				x+=XSPEED;
				y+=YSPEED;
				break;
			case LD:
				x-=XSPEED;
				y+=YSPEED;
				break;
			case LU:
				x-=XSPEED;
				y-=YSPEED;
				break;
		}
		//让坦克不能出界
		if(x<0)x=0;
		if(y<25)y=25;
		if(x+Tank.WIDTH>TankClient.GAME_WIDTH)x=TankClient.GAME_WIDTH-Tank.WIDTH;
		if(y+Tank.HEIGHT>TankClient.GAME_HEIGHT)y=TankClient.GAME_HEIGHT-Tank.HEIGHT;
		
		if(!good){
			Direction[] dirs=Direction.values();//把枚举元素变成枚举数组
			if(step==0){
				step=r.nextInt(12)+3;
				int rn=r.nextInt(dirs.length-1);//让随机数在数组的长度区间内取整
				dir=dirs[rn];//每移动一次改变下移动方向
			}
			step--;
			if(r.nextInt(40)>38)this.fire();//让敌军坦克开火,5%的概率打出一发炮弹
		}
	}
	
	/**
	 * 坦克对键盘按下事件做出响应
	 * @param e 传入事件的引用
	 */
	public void keyPressed(KeyEvent e){
		int key=e.getKeyCode();//拿到所按下键的Ascii码值
		switch(key){//判断所按下的键是否是上下左右
			case KeyEvent.VK_F2:
				if(!this.live){
					this.life=100;//满血复活
					this.live=true;
				}
				break;
			case KeyEvent.VK_UP:
				bU=true;//按下键后只改变方向
				break;
			case KeyEvent.VK_DOWN:
				bD=true;
				break;
			case KeyEvent.VK_LEFT:
				bL=true;
				break;
			case KeyEvent.VK_RIGHT:
				bR=true;
				break;
		}
		locateDirection();//定位下坦克移动的方向
	}
	
	//坦克开火,返回一颗炮弹
	private Missile fire() {
		if(!live) return null;//若坦克已死,则不让它开火
		int x=this.x+Tank.WIDTH/2-Missile.WIDTH/2;//让炮弹重坦克的中心位置打出
		int y=this.y+Tank.HEIGHT/2-Missile.HEIGHT/2;
		Missile m=new Missile(x, y, good,ptDir,tc);//根据炮筒方向,和坦克是否是我军和敌军来新建这颗炮弹
		tc.missiles.add(m);//每释放一次ctrl键,就添加new炮弹添加到arrayList中去,但是每次都new总会把内存耗光的时候
		return m;
	}
	//根据方向开火
	private Missile fire(Direction dir) {
		if(!live) return null;//若坦克已死,则不让它开火
		int x=this.x+Tank.WIDTH/2-Missile.WIDTH/2;//让炮弹重坦克的中心位置打出
		int y=this.y+Tank.HEIGHT/2-Missile.HEIGHT/2;
		Missile m=new Missile(x, y, good,dir,tc);//根据炮筒方向,和坦克是否是我军和敌军来新建这颗炮弹
		tc.missiles.add(m);//每释放一次ctrl键,就添加new炮弹添加到arrayList中去,但是每次都new总会把内存耗光的时候
		return m;
	}
	
	
	/**
	 * 坦克对键盘释放做出响应
	 * @param e 传入事件的引用
	 */
	public void keyReleased(KeyEvent e){
		int key=e.getKeyCode();//拿到所按下键的Ascii码值
		switch(key){//判断所按下的键是否是上下左右
		case KeyEvent.VK_CONTROL:  //如果释放的是ctrl键盘,则打出一发炮弹
			fire();//开火后给客户端的炮弹新建出来
		   break;
		case KeyEvent.VK_UP:
			bU=false;//按下键后只改变方向
			break;
		case KeyEvent.VK_DOWN:
			bD=false;
			break;
		case KeyEvent.VK_LEFT:
			bL=false;
			break;
		case KeyEvent.VK_RIGHT:
			bR=false;
			break;
		case KeyEvent.VK_A:
			superFire();
			break;
		}
		locateDirection();//定位下坦克移动的方向
	}
	
	//因为不知道到底按了哪几个键,所以最终要确定坦克的移动方向
	void locateDirection(){
		if(bU&&!bD&&!bL&&!bR) dir=Direction.U;//若bU为true,其他的都为false则表示只按下了上键
		if(!bU&&bD&&!bL&&!bR) dir=Direction.D;
		if(!bU&&!bD&&bL&&!bR) dir=Direction.L;
		if(!bU&&!bD&&!bL&&bR) dir=Direction.R;
		if(bU&&!bD&&!bL&&bR) dir=Direction.RU;
		if(!bU&&bD&&!bL&&bR) dir=Direction.RD;
		if(!bU&&bD&&bL&&!bR) dir=Direction.LD;
		if(bU&&!bD&&bL&&!bR) dir=Direction.LU;
		if(!bU&&!bD&&!bL&&!bR) dir=Direction.STOP;
	}
	
	/**
	 * @return 返回坦克的矩形
	 */
	public Rectangle getRect(){
		return new Rectangle(x, y, WIDTH, HEIGHT);
	}
	/**
	 *坦克撞墙检测
	 * @param w 传入墙体的引用
	 * @return 坦克是否撞墙 
	 */
	public boolean collidesWithWall(Wall w){
		if(this.live&&this.getRect().intersects(w.getRect())){
			this.stay();//撞墙了回到上一个位置
			return true;
		}
		return false;
	}
	//撞墙则返回上一个坐标
	private void stay(){
		x=oldX;
		y=oldY;
	}
	/**
	 * 坦克与坦克碰撞检测
	 * @param tanks 坦克的数组
	 * @return 坦克与坦克是否相撞
	 */
	public boolean collidesWithTanks(List<Tank> tanks){
		for(int i=0;i<tanks.size();i++){
			Tank t=tanks.get(i);
			if(this!=t){
				if(this.live&&t.isLive()&&this.getRect().intersects(t.getRect())){
					t.stay();
					this.stay();
					return true;
				}
			}
		}
		return false;
	}
	//坦克是否碰到河边
	public boolean collidesWithLine(){
		if(
				this.live&&(//不让坦克穿过河流
									this.getRect().intersectsLine(430, 130, 180, 220)||
									this.getRect().intersectsLine(180, 220, 220, 320)||
									this.getRect().intersectsLine(430, 130, 525, 180)||
									//下半河道
									this.getRect().intersectsLine(615, 220, 635, 220)||//10,11
									this.getRect().intersectsLine(615, 220, 605, 250)||//10,13
									this.getRect().intersectsLine(635, 220, 605, 250)||//11,13
									this.getRect().intersectsLine(570, 330, 635, 380)||//14,15
									this.getRect().intersectsLine(570, 330, 380, 400)||//14,16
									this.getRect().intersectsLine(380, 400, 280, 380)//16,17
									
						)){
			this.stay();
			return true;
		}
		return false;
	}
	
	
	//超级散弹
	private void superFire(){
		Direction[] dir=Direction.values();
		for(int i=0;i<8;i++){
			fire(dir[i]);//每个方向都发射炮弹
		}
	}
	//血条
	private class BloodBar{
		public void draw(Graphics g){
			Color c=g.getColor();
			g.setColor(Color.RED);
			g.drawRect(x, y, WIDTH, 3);//外血槽
			int w=WIDTH*life/100;
			g.fillRect(x, y, w, 3);
			g.setColor(c);
		}
	}
	
	/**
	 * 坦克加血
	 * @param b 血块的引用
	 * @return 坦克是否加到血
	 */
	 public boolean eat(Blood b){
		 if(tc.tanks.size()==0){
			 b.setLive(true);//敌军坦克死光,奖励个包子
		 }
		 if(this.live&&b.isLive()&&this.getRect().intersects(b.getRect())){
			 this.setLife(100);//加了血直接满血
			 b.setLive(false);//吃了血块,血块死亡
			 return true;
			}
			return false;
	 }
	
}
